package com.gviiii.pprf.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.util.concurrent.DefaultThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class RfNioClient implements InitializingBean, DisposableBean, ApplicationListener<ApplicationEvent> {

    private static final Logger logger = LoggerFactory.getLogger(RfNioClient.class);

    private ExecutorService executor= Executors.newFixedThreadPool(10,new DefaultThreadFactory("RfClient"));

    public static Channel channel;

    private Bootstrap bootstrap;

    private NioEventLoopGroup eventLoopGroup;

    private InetSocketAddress localAddress;

    private RfChannelHandler rfChannelHandler;

    private static Map<String, Integer> msgTags;

    public RfNioClient() {
    }

    public RfNioClient(InetSocketAddress localAddress) {
        this.localAddress = localAddress;
    }

    public void start() {
        bootstrap = new Bootstrap();
        eventLoopGroup = new NioEventLoopGroup();

//        LineBasedFrameDecoder lbfd = new LineBasedFrameDecoder(1024);
        rfChannelHandler = new RfChannelHandler();
        msgTags = rfChannelHandler.getMsgTags();
//        final NettyCodec nettyCodec = new NettyCodec();

        bootstrap
                .group(eventLoopGroup)
                .channel(NioSocketChannel.class)
//                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline()
//                                .addLast(lbfd)
                                .addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer(";".getBytes())))
                                .addLast(new NettyEncoder())
                                .addLast(new NettyDecoder())
                                .addLast(rfChannelHandler);

                    }
                });
        doConnect();
    }

    public void reconnet() {
        if (Objects.nonNull(channel)) {
            if (!channel.isActive()) {
//                channel.connect(localAddress).syncUninterruptibly();
//                ChannelFuture future = bootstrap.connect(localAddress);
//                future.syncUninterruptibly();
//                channel= future.channel();
                doConnect();
            }
        } else {
            doConnect();
        }
    }

    private void doConnect() {
        ChannelFuture future = bootstrap.connect(localAddress);
        try {
            future.sync().await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        channel = future.channel();
        logger.info("客户端启动");
    }

    /**
     * 停止rf client
     */
    public void stop() {
//        NettyMessage message = new NettyMessage();
//        message.setHeader(Header.DISCONNECTED_MSG);
//        channel.writeAndFlush(message);
        if (channel != null) {
            channel.close();
            channel.disconnect();
        }

        if (bootstrap != null)
            eventLoopGroup.shutdownGracefully();
    }

    /**
     * 赋值
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        localAddress = new InetSocketAddress("127.0.0.1", 4002);
    }

    public Channel getChannel() {
        return channel;
    }

    /**
     * 发送消息
     *
     * @param s
     */
    public static void send(NettyMessage s) {
        if (Objects.nonNull(channel)) {
            if (channel.isActive()) {
                channel.writeAndFlush(s);
//            try {
//                if (!channel.closeFuture().await(1000)) {
//                    send(s);
//                }
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            }
        }
    }

    public static Map<String, Integer> getMsgTags() {
        return msgTags;
    }

    /**
     * 销毁bean回调 执行停止rf client
     *
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        stop();
    }

    /**
     * 容器事件
     *
     * @param event
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        //容器启动 启动rf client
        if (event instanceof ContextRefreshedEvent) {
            if (Objects.isNull(bootstrap)) {
//                start();
            }
        }
        //发送与rf server 断开连接信息
        if (event instanceof ContextClosedEvent) {
            logger.info("closed....");
            send(new NettyMessage(Header.DISCONNECTED_MSG, "255.255.255.255:4003"));
            stop();
        }
        if (event instanceof ContextStoppedEvent) {
            logger.info("stop....");
            send(new NettyMessage(Header.DISCONNECTED_MSG, "255.255.255.255:4003"));
            stop();
        }
    }
}
